#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : ui_stdf.py
@Author  : Link
@Time    : 2022/5/2 10:44
@Mark    : 
"""
import math
import sys
import datetime as dt
from typing import Union, List
from pydoc import help

import numpy as np
import pandas as pd
import win32api
from PySide2.QtCore import Slot, QTimer, Qt, Signal
from PySide2.QtGui import QCloseEvent
from PySide2.QtWidgets import QMainWindow, QApplication, QWidget, QMessageBox, QFileDialog

from pyqtgraph.dockarea import *

from ui_component.ui_common.ui_console import ConsoleWidget
from ui_component.ui_to_analysis_stdf.ui_designer.ui_home_load import Ui_MainWindow
from ui_component.ui_to_analysis_stdf.utils import TreeUtils, QTableUtils
from ui_component.ui_to_analysis_stdf.ui_components.ui_file_load_widget import FileLoadWidget  # 文件选取
from ui_component.ui_to_analysis_stdf.ui_components.ui_tree_load_widget import TreeLoadWidget  # 载入的数据选取
from ui_component.ui_to_analysis_stdf.ui_components.ui_table_load_widget import TableLoadWidget  # 测试项选取
from workspace_core.li import DfCore, SummaryCore


class StdfLoadUi(QMainWindow, Ui_MainWindow):
    """
    懒加载界面
    """
    closeSignal = Signal(int)
    parent = None

    def __init__(self, parent=None, space_nm=1, path_select=False, select=True):
        super(StdfLoadUi, self).__init__(parent)
        self.parent = parent
        self.setupUi(self)
        self.space_nm = space_nm
        self.li = DfCore()
        self.summary = SummaryCore()
        self.title = "STDF数据载入空间: {}".format(space_nm)
        self.setWindowTitle(self.title)

        self.area = DockArea()
        self.setCentralWidget(self.area)
        " FileLoadWidget用来载入数据文件，内部用到多进程&多线程 "
        self.file_select_widget = FileLoadWidget(self, space_nm=space_nm)
        self.dock_file_load = Dock("STDF File Select", size=(400, 100))
        self.dock_file_load.addWidget(self.file_select_widget)
        self.area.addDock(self.dock_file_load)

        " TreeLoadWidget用来载入和配对内部数据，会占用到大量的IO资源 "
        self.tree_load_widget = TreeLoadWidget(self)
        dock_tree_load = Dock("Data Tree Select & Config", size=(200, 300))
        dock_tree_load.addWidget(self.tree_load_widget)
        self.area.addDock(dock_tree_load, "bottom", self.dock_file_load)
        # self.area.moveDock(self.dock_file_load, 'above', dock_tree_load)

        " TableLoadWidget用来载入和配对内部数据，会占用到大量的IO资源, 并且是作为主要的分析界面 "
        self.table_load_widget = TableLoadWidget(self)
        dock_table_load = Dock("Data TEST NO&ITEM Analysis", size=(200, 300))
        dock_table_load.addWidget(self.table_load_widget)
        self.area.addDock(dock_table_load, "right", dock_tree_load)
        # self.area.moveDock(dock_tree_load, 'above', dock_table_load)

        " Console "
        text = """
        载入的功能包: np(numpy), pd(pandas), math
        载入的函数库: util(通过help(util)查询功能)
        载入的数据:
            点击RUN后会被刷新 
            li: 集中数据, 通过help(li)查看
        RUN.
        """
        self.namespace = {
            "np": np,
            "pd": pd,
            "math": math,
            # "util": util,
            # "plt": plt,  # 按需导入
            "help": help,
            "li": self.li,
            "summary": self.summary
        }
        self.console = ConsoleWidget(parent=self, namespace=self.namespace, text=text)
        self.dock_console_load = Dock("Python Console", size=(400, 100))
        self.dock_console_load.addWidget(self.console)
        self.area.addDock(self.dock_console_load, "bottom")
        # self.area.moveDock(self.dock_file_load, 'above', dock_console_load)
        "------------------------------------------------------------------------------"
        self.area.restoreState({'main': ('vertical', [('dock', 'STDF File Select', {}), (
            'horizontal', [('dock', 'Data Tree Select & Config', {}), ('dock', 'Python Console', {})],
            {'sizes': [595, 822]}), ('dock', 'Data TEST NO&ITEM Analysis', {})], {'sizes': [210, 269, 365]}),
                                'float': []})
        self.dock_console_load.hide()  # 可以显示和隐藏
        self.init_signal()
        if select:
            if path_select:
                self.file_select_widget.first_directory_select()
            else:
                self.file_select_widget.first_select()
        # self.setFixedSize(1366, 768)

    def init_signal(self):
        self.file_select_widget.dataSignal.connect(self.mdi_space_data_emit)
        self.file_select_widget.messageSignal.connect(self.mdi_space_message_emit)
        self.li.calculation_cpk_signal.connect(self.calculation_cpk)
        self.li.front_df_signal.connect(lambda: self.li.calculation_cpk())
        self.li.message.connect(lambda x: self.message_show(x))

    @Slot(tuple)
    def mdi_space_data_emit(self, data: tuple):
        self.summary.set_data(data)
        self.li.set_limit_dict(self.summary.limit_dict)
        self.tree_data_load()

    @Slot(SummaryCore)
    def merge_data_emit(self, data: SummaryCore):
        self.summary = data
        self.li.set_limit_dict(self.summary.limit_dict)
        self.tree_data_load()

    def tree_data_load(self):
        tree_data = self.summary.get_summary_tree()
        TreeUtils.set_data_to_tree(self.tree_load_widget.treeWidget, tree_data, True)
        self.widget_change_color(widget=self.tree_load_widget, background_color="#3316C6")
        self.tree_load_widget.treeWidget.expandAll()

    @Slot(object, object)
    def calculation_cpk(self, cpk_list, cpk_dict):
        if not cpk_dict or not cpk_list:
            return self.message_show("CPK数据计算失败!")
        self.table_load_widget.cpk_info_table.setData(cpk_list)
        if self.table_load_widget.checkBox.isChecked():
            self.table_load_widget.cpk_info_table.sortByColumn(11, Qt.SortOrder.DescendingOrder)
        else:
            self.table_load_widget.cpk_info_table.sortByColumn(0, Qt.SortOrder.AscendingOrder)
        self.mdi_space_message_emit("数据空间解析处理完成")
        self.widget_change_color(widget=self.table_load_widget, background_color="#3316C6")

    @Slot()
    def on_action_dock_structure_triggered(self):
        """ 将 area 布局保存在泡菜中 """
        state = self.area.saveState()
        print(state)

    @Slot()
    def on_action_sava_data_triggered(self):
        """ 将数据保存在csv文件中 """
        self.save_file_function(self.li.df)

    @Slot()
    def on_action_console_triggered(self):
        if self.action_console.isChecked():
            self.dock_console_load.show()
        else:
            self.dock_console_load.hide()

    @Slot()
    def on_action_limit_triggered(self):
        self.summary.show_limit_diff()

    @Slot(str)
    def mdi_space_message_emit(self, message: str):
        """
        append message
        :param message:
        :return:
        """
        self.statusbar.showMessage("==={}==={}===".format(dt.datetime.now().strftime("%H:%M:%S"), message))

    @staticmethod
    def widget_change_color(widget: QWidget, background_color: str = "#333333"):
        """
        给widget改变背景色, 改变前 widget.setAttribute(Qt.WidgetAttribute.WA_StyledBackground)
        :param widget:
        :param background_color:
        :return:
        """
        widget.setStyleSheet("background-color: %s;" % background_color)
        QTimer.singleShot(500, lambda: widget.setStyleSheet(""))

    def message_show(self, text: str) -> bool:
        res = QMessageBox.question(self, '待确认', text,
                                   QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.Yes)
        if res == QMessageBox.Yes:
            return True
        else:
            return False

    def get_text_column(self) -> Union[List[str], None]:
        return QTableUtils.get_table_widget_test_text(self.table_load_widget.cpk_info_table)

    def save_file_function(self, data_object, file_name="", _open=False):
        if data_object is None:
            return self.message_show('无数据, 无法保存!!! ')
        if any(data_object):
            save_file, suffix = QFileDialog.getSaveFileName(None, caption='保存文件', directory=f'D:/{file_name}',
                                                            filter='csv(*.csv);;excel(*.xlsx)')
            if suffix == 'csv(*.csv)':
                data_object.to_csv(save_file, encoding='utf_8_sig', index=False)
            elif suffix == 'excel(*.xlsx)':
                data_object.to_excel(save_file, encoding='utf_8_sig', index=False)
            else:
                self.statusbar.showMessage('取消数据保存')
                return
            self.statusbar.showMessage(f'数据保存成功,路径在:>>>{save_file}')
            if _open:
                win32api.ShellExecute(0, 'open', save_file, '', '', 1)
        else:
            self.message_show(f'未查询 空数据无法保存!!! ')

    def closeEvent(self, a0: QCloseEvent) -> None:
        """
        删除mdi时, 需要将与其对应的chart也删除
        """
        self.parent = None
        self.closeSignal.emit(self.space_nm)
        return super(StdfLoadUi, self).closeEvent(a0)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = StdfLoadUi()
    win.show()
    sys.exit(app.exec_())
